Skip to content

feat(changelog): BitRouter-refined drafts + multi-channel announce - #29

Closed
SPIKESPIGEL404 wants to merge 1 commit into
mainfrom
feat/changelog-refine-and-announce
Closed

feat(changelog): BitRouter-refined drafts + multi-channel announce#29
SPIKESPIGEL404 wants to merge 1 commit into
mainfrom
feat/changelog-refine-and-announce

Conversation

@SPIKESPIGEL404

Copy link
Copy Markdown
Contributor

What

Extends the existing changelog sync into the full refine → gate → publish loop for both BitRouter (OSS) and BitRouter Cloud, per the two-repo design (product repos just dispatch; all refinement/marketing lives here).

release:published (bitrouter | bitrouter-cloud)
  → repository_dispatch: bitrouter-release  (product repo — see companion PR)
  → sync-changelog.mjs + BitRouter refine ──► draft content/changelog/<ver>.mdx
  → PR "changelog/sync"  (unchanged review gate — curate + merge)
  → site rebuild → changelog page + RSS/Atom     (docs publish, already exists)
  → announce-channels.yml → Discord · X (xurl) · Resend   (NEW)

Changes

File Change
scripts/sync-changelog.mjs Optional BitRouter refine pass (dogfood) → polished prose + title/description. Deterministic fallback with no key. New cloud product path (inline body, cloud-<slug>.mdx).
source.config.ts changelog frontmatter gains optional product: oss | cloud.
.github/workflows/sync-changelog.yml Pass product / inline body / BITROUTER_API_KEY from the dispatch.
scripts/announce-channels.mjs (new) Fan out a merged entry to Discord / X / Resend; per-channel copy optionally BitRouter-spun; graceful skips; version tiering; backfill age-guard.
.github/workflows/announce-channels.yml (new) Runs the fan-out on merged content/changelog/**; once-only via announced/<slug> tags.

Tiering: *-alpha/beta/rc* & patches → Discord only; x.y.0 → Discord + X + email.

Safety

  • Non-breaking: no BITROUTER_API_KEY → the existing deterministic draft; no channel secret → that channel is skipped (logged, non-fatal). Safe to merge before anything is wired.
  • Idempotent: each entry announced once (announced/<slug> tag); backfill merges older than 14d are skipped.
  • Review gate (changelog/sync PR) and docs/RSS publish are unchanged.

Companion change (product repos)

Needs bitrouter/bitrouter (and bitrouter-cloud) to fire the release dispatch so sync runs on release instead of the daily cron — a small notify-release.yml (already drafted on the bitrouter side). Cloud sends product: cloud + inline body since this repo can't read the private repo.

Secrets / vars to add here

Secrets: BITROUTER_API_KEY (refine + channel copy), DISCORD_WEBHOOK_OSS, DISCORD_WEBHOOK_CLOUD, XURL_TOKENS, RESEND_API_KEY
Variables: SITE_URL, RESEND_AUDIENCE_OSS, RESEND_AUDIENCE_CLOUD, RESEND_FROM

Tested

  • node --check + YAML parse on all files.
  • Deterministic sync of v1.0.0-alpha.22 → valid .mdx with product frontmatter.
  • Fan-out dry-run: prerelease → Discord only; x.y.0 cloud → all three; every channel skipped gracefully with no secrets; age-guard drops a 556d-old entry. All exit 0.

Verify before enabling (couldn't test without live creds)

  • The refine LLM call path (fetch + JSON parse) — proven by the deterministic fallback + parser, but not exercised against a live model here.
  • xurl install URL / token-store path in announce-channels.yml — pin to your version.
  • Resend Broadcasts shape + a verified RESEND_FROM domain.

🤖 Generated with Claude Code

Extend the existing changelog sync into the refine → gate → publish loop for
both BitRouter (OSS) and BitRouter Cloud.

- sync-changelog.mjs: optional BitRouter refine pass (dogfood via
  api.bitrouter.ai) turns raw git-cliff bullets into benefit-oriented prose +
  a tighter title/description. Falls back to the deterministic draft when
  BITROUTER_API_KEY is absent, so nothing breaks without a key. Adds a `cloud`
  product path (inline body, cloud-<slug>.mdx) so the private repo is never
  fetched here.
- source.config.ts: changelog frontmatter gains optional `product` (oss|cloud).
- sync-changelog.yml: pass product/body/refine-key through from the dispatch.
- announce-channels.mjs + announce-channels.yml (new): on a merged changelog
  entry, fan out to Discord / X (xurl) / Resend, tiered by version
  (alpha/patch → Discord only; x.y.0 → all). Per-channel copy is optionally
  spun by BitRouter, else derived deterministically. Every channel skips
  gracefully when unconfigured; entries are announced once (announced/<slug>
  tag) and a backfill age-guard prevents old-release spam.

The review gate is unchanged: the changelog/sync PR. The docs page + RSS/Atom
feed still publish via the site rebuild on merge.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@SPIKESPIGEL404

Copy link
Copy Markdown
Contributor Author

Superseded by the changelog refactor on claude/changelog-refactor-6d257c.

This branch rewrote scripts/sync-changelog.mjs and sync-changelog.yml heavily enough that rebasing here would have meant resolving conflicts against code that no longer exists, so the ideas were reimplemented rather than merged. Where each piece went:

Kept, moved up a layer. The tiering instinct here — prereleases and patches get less than x.y.0 — was right, but it lived in tierFor() inside the announce script and was recomputed from a version regex at post time. The page never saw it, and a human who judged an otherwise-routine release important had no way to say so. It is now significance in the entry's frontmatter, read by the page, the nav dot, RSS and the announcer alike (lib/announce-tiers.mjs). Promoting an entry promotes it everywhere.

Kept, then removed. The BitRouter refine pass was reimplemented against the new sync and unit-tested, then removed at the author's request before it ever ran — it only fired for non-routine entries, and every upstream release is a routine alpha. Recoverable from history if wanted.

Dropped deliberately. The LLM-written per-channel copy. Notable and highlight entries now pass a curation gate, so their title and description are human-written; re-spinning that into an auto-posted public tweet is risk without upside. Announce copy is deterministic.

Changed on safety grounds.

  • Email is created as a draft Resend broadcast and never sent. A workflow mailing a list with nobody having read the message is not retractable.
  • Two brakes before anything posts: ANNOUNCE_ENABLED must be true, and the announce environment takes required reviewers.
  • xurl is pinned via vars.XURL_VERSION and the || true on the download is gone — a failed install used to leave the job green and simply never post.

Bug this PR would have shipped. The announce workflow triggered only on push to main. The routine-publish path pushes with GITHUB_TOKEN, and GitHub does not fire workflows for such a push — so routine releases would never have been announced, with nothing in the logs to say so. Announcing is now a workflow_call reusable workflow invoked by the sync, keeping push for human PR merges.

Deferred. The product: oss | cloud path, until the page can label and filter by product — otherwise cloud entries would interleave into the same undifferentiated list.

Thanks — the tiering idea is the backbone of the whole refactor.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants